﻿namespace UnitTestInjector
{
    #region Usings

    using Localizations;
    using System;

    #endregion Usings

    public abstract class InjectorTestClass<TDependencyResolver> : BaseTestClass
        where TDependencyResolver : IDependencyResolver
    {
        protected virtual void TestExpectedArgumentException<TException>(Action<IDependencyResolver> testMethod,
            string parameterName)
            where TException : ArgumentException
        {
            if (testMethod == null)
            {
                throw new ArgumentNullException("testMethod",
                    Strings.TestExpectedArgumentExceptionParameterNameIsInvalidExceptionMessage);
            }

            if (string.IsNullOrWhiteSpace(parameterName))
            {
                throw new ArgumentException(Strings.TestExpectedArgumentExceptionParameterNameIsInvalidExceptionMessage,
                    "parameterName");
            }

            try
            {
                testMethod(CreateDependencyResolver());
            }
            catch (Exception ex)
            {
                UnitTestInjectorAssert.IsInstanceOfType<TException>(ex);

                var exception = ex as ArgumentNullException;
                UnitTestInjectorAssert.AreEqual(parameterName,
                    exception != null ? exception.ParamName : ex.Message);

                return;
            }

            throw new ArgumentException(Strings.TestExpectedArgumentExceptionNoExceptionRaised, "testMethod");
        }

        protected virtual void TestExpectedException<TException>(Action<IDependencyResolver> testMethod,
            string exceptionMessage)
            where TException : Exception
        {
            if (testMethod == null)
            {
                throw new ArgumentNullException("testMethod",
                    Strings.TestExpectedArgumentExceptionParameterNameIsInvalidExceptionMessage);
            }

            try
            {
                testMethod(CreateDependencyResolver());
            }
            catch (Exception ex)
            {
                UnitTestInjectorAssert.IsInstanceOfType<TException>(ex);
                UnitTestInjectorAssert.AreEqual(exceptionMessage, ex.Message);
                return;
            }

            throw new ArgumentException(Strings.TestExpectedArgumentExceptionNoExceptionRaised, "testMethod");
        }

        protected virtual void Test(Action<TDependencyResolver> testMethod)
        {
            testMethod(CreateDependencyResolver());
        }

        protected abstract TDependencyResolver CreateDependencyResolver();
    }

    public abstract class InjectorTestClass<TClassToTest, TDependencyResolver> : InjectorTestClass<TDependencyResolver>
        where TClassToTest : class
        where TDependencyResolver : IDependencyResolver
    {
        protected TClassToTest ResolveClassToTest(IDependencyResolver dependencyResolver)
        {
            var implementation = dependencyResolver.Resolve<TClassToTest>();

            UnitTestInjectorAssert.IsNotNull(implementation);

            return implementation;
        }
    }
}